package cc.rengu.igas.channel.upac.core.packswitch;

import cc.rengu.igas.channel.upac.common.constant.UpacConfigConstant;
import cc.rengu.igas.channel.upac.common.constant.UpacParamConstant;
import cc.rengu.igas.channel.upac.common.constant.UpacTreeNodeConstant;
import cc.rengu.igas.channel.upac.common.enums.RespCodeEnum;
import cc.rengu.igas.channel.upac.common.util.UpacSecurityUtil;
import cc.rengu.jradp.packetswitch.IncomingPackSwitchImpl;
import cc.rengu.jradp.packetswitch.OutgoingPackSwitchImpl;
import cc.rengu.oltp.service.common.constant.TreeNodeConstant;
import cc.rengu.oltp.service.common.dao.DstChannelCfgMapper;
import cc.rengu.oltp.service.common.dao.SrcChannelInfoMapper;
import cc.rengu.oltp.service.common.dao.impl.DstChannelCfgMapperImpl;
import cc.rengu.oltp.service.common.dao.impl.SrcChannelInfoMapperImpl;
import cc.rengu.oltp.service.common.entity.DstChannelCfg;
import cc.rengu.oltp.service.common.entity.SrcChannelInfo;
import cc.rengu.oltp.service.common.entity.SysParam;
import cc.rengu.oltp.service.common.enums.ChannelEnum;
import cc.rengu.oltp.service.model.BizException;
import cc.rengu.oltp.service.realize.SysParamService;
import cc.rengu.oltp.service.realize.impl.SysParamServiceImpl;
import cc.rengu.oltp.utility.util.DateUtil;
import cc.rengu.oltp.utility.util.XmlTreeUtil;
import cc.rengu.utility.cache.UnifiedCache;
import cc.rengu.utility.log.RgLog;
import cc.rengu.utility.log.RgLogger;

import java.net.URLDecoder;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * 银联全渠道通讯报文解包前后、组前包后实现类
 * Created by 王成 on 2018/12/27.
 */
public class UpacServerPackSwitch implements IncomingPackSwitchImpl, OutgoingPackSwitchImpl {

    @Override
    public byte[] beforeInComPackSwitch(byte[] bytes) throws Exception {
        RgLogger rglog = RgLog.getLogger(this.getClass().getName());
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        SysParamService sysParamService = new SysParamServiceImpl();
        /*根据url服务名转换交易码*/
        String hostUrl = xmlTreeUtil.getXmlTreeStringValue("_MESSAGEHEAD/http/Host");
        rglog.debug("通知地址!url<{}>", hostUrl);
        String sysSrcId = ChannelEnum.UPAC.getChannelType();
        /* 赋值默认机构、渠道、交易细分 */
        xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.VERSION, "1.0.0");
        xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.TRANS_DATE, DateUtil.getCurrentDate());
        xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.TRANS_TIME, DateUtil.getCurrentTime());
        xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.TRANS_CHANNEL_ID, sysSrcId);
        xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.CHANNEL_ID, "*");
        xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.MSG_SRC_ID, ChannelEnum.UPAC.getChannelType());
        xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.SRC_SYS_ID, ChannelEnum.UPAC.getChannelType());
        xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.BIZ_TYPE, UpacParamConstant.DEFAULT_BIZ_TYPE);
        String recvData = new String(bytes);
        if (!recvData.isEmpty()) {
            Map<String, String> recvMap = new HashMap<String, String>();
            recvMap = UpacSecurityUtil.parseJsonString(recvData);
            String charset;
            if (recvMap.get("encoding") != null) {
                charset = recvMap.get("encoding");
                rglog.trace("编码格式为:{}", charset);
            } else {
                rglog.trace("默认UTF-8编码格式...");
                charset = "utf-8";
            }
            String[] kvs = recvData.split("&");
            for (String kv : kvs) {
                String[] tmp = kv.split("=");
                if (tmp.length >= 2) {
                    String key = tmp[0];
                    String value = URLDecoder.decode(tmp[1], charset);
                    recvMap.put(key, value);
                }
            }
            String mchntNo = recvMap.get("merId");
            DstChannelCfgMapper dstChannelCfgMapper = new DstChannelCfgMapperImpl();
            List<DstChannelCfg> dstChannelCfgList = dstChannelCfgMapper.loadAllDstChannelCfg();
            if (dstChannelCfgList == null || dstChannelCfgList.isEmpty()) {
                rglog.error("无通道配置信息，未知法人行交易");
                return new byte[0];
            }
            Predicate<DstChannelCfg> chnlIdFilter = p -> ChannelEnum.UPAC.getChannelType().equals(p.getDstChannelId());
            Predicate<DstChannelCfg> mchntNoFilter = p -> mchntNo.equals(p.getProviderMchntNo());
            dstChannelCfgList = dstChannelCfgList.stream().filter(chnlIdFilter.and(mchntNoFilter)).collect(Collectors.toList());
            if (dstChannelCfgList.isEmpty()) {
                rglog.error("根据通道id<{}>、银联商户号<{}>查无无通道配置信息，未知法人行交易", ChannelEnum.UPAC.getChannelType(), mchntNo);
                return new byte[0];
            }
            String instId = dstChannelCfgList.get(0).getInstId();
            xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.INST_ID, instId);
            xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.HEADER_INST_ID, instId);
            /* 获取通道配置信息 */
            SrcChannelInfoMapper srcChannelInfoMapper = new SrcChannelInfoMapperImpl();
            SrcChannelInfo srcChannelInfo = srcChannelInfoMapper.selectSrcChannelInfoByPrimaryKey(instId, ChannelEnum.UPAC.getChannelType(), "*");
            if (null == srcChannelInfo) {
                rglog.error("获取渠道<{}>配置信息失败!", ChannelEnum.UPAC.getChannelType());
                throw new BizException(RespCodeEnum.CHANNEL_CONFIG_NOT_EXIST.getRespCode(), RespCodeEnum.CHANNEL_CONFIG_NOT_EXIST.getRespDesc());
            }
            xmlTreeUtil.setXmlTreeObjectValue(UpacTreeNodeConstant.SRC_CHANNEL_INFO, srcChannelInfo);
            /* 加载银联根证书跟中级证书 */
            /*优先从系统缓存读取*/
            X509Certificate rootCert = (X509Certificate) UnifiedCache.get(UpacParamConstant.CERT_KEY_CACHE, instId + UpacConfigConstant.UPAC_CONF_NODE + UpacConfigConstant.UPAC_ROOT_CERT_PATH);
            if (rootCert == null) {
                SysParam sysParam = sysParamService.getSysParamInfo(instId, UpacConfigConstant.UPAC_CONF_NODE, UpacConfigConstant.UPAC_ROOT_CERT_PATH);
                if (sysParam == null) {
                    rglog.error("未配置根证书路径");
                    xmlTreeUtil.setXmlTreeStringValue(UpacTreeNodeConstant.respCode, RespCodeEnum.VERIFY_SIGN_ERROR.getRespCode());
                    xmlTreeUtil.setXmlTreeStringValue(UpacTreeNodeConstant.respDesc, RespCodeEnum.VERIFY_SIGN_ERROR.getRespCode());
                    return new byte[0];
                }
                rootCert = UpacSecurityUtil.initCert(sysParam.getParamValue());
                if (rootCert == null) {
                    rglog.error("从路径初始化根证书失败，根证书路径 = <{}>", sysParam.getParamValue());
                    xmlTreeUtil.setXmlTreeStringValue(UpacTreeNodeConstant.respCode, RespCodeEnum.VERIFY_SIGN_ERROR.getRespCode());
                    xmlTreeUtil.setXmlTreeStringValue(UpacTreeNodeConstant.respDesc, RespCodeEnum.VERIFY_SIGN_ERROR.getRespCode());
                    return new byte[0];
                }
                /*加载到缓存*/
                UnifiedCache.set(UpacParamConstant.CERT_KEY_CACHE, instId + UpacConfigConstant.UPAC_CONF_NODE + UpacConfigConstant.UPAC_ROOT_CERT_PATH, rootCert);
            }
            X509Certificate middleCert = (X509Certificate) UnifiedCache.get(UpacParamConstant.CERT_KEY_CACHE, instId + UpacConfigConstant.UPAC_CONF_NODE + UpacConfigConstant.UPAC_MIDDLE_CERT_PATH);
            if (middleCert == null) {
                SysParam sysParam = sysParamService.getSysParamInfo(instId, UpacConfigConstant.UPAC_CONF_NODE, UpacConfigConstant.UPAC_MIDDLE_CERT_PATH);
                if (sysParam == null) {
                    rglog.error("未配置中级证书路径");
                    xmlTreeUtil.setXmlTreeStringValue(UpacTreeNodeConstant.respCode, "11");
                    xmlTreeUtil.setXmlTreeStringValue(UpacTreeNodeConstant.respDesc, "验证签名失败");
                    return new byte[0];
                }
                middleCert = UpacSecurityUtil.initCert(sysParam.getParamValue());
                if (middleCert == null) {
                    rglog.error("从路径初始化中级证书失败,中级证书路径 = <{}>", sysParam.getParamValue());
                    xmlTreeUtil.setXmlTreeStringValue(UpacTreeNodeConstant.respCode, "11");
                    xmlTreeUtil.setXmlTreeStringValue(UpacTreeNodeConstant.respDesc, "验证签名失败");
                    return new byte[0];
                }
                /*加载到缓存*/
                UnifiedCache.set(UpacParamConstant.CERT_KEY_CACHE, instId + UpacConfigConstant.UPAC_CONF_NODE + UpacConfigConstant.UPAC_MIDDLE_CERT_PATH, middleCert);
            }
            /* 验证签名,公钥从recvMap获取 */
            if (UpacSecurityUtil.verifySign(UpacSecurityUtil.covertResultMap2String(recvMap), "PubKey", middleCert, rootCert)) {
                rglog.info("签名验证成功!");
                return UpacSecurityUtil.covertResultMap2String(recvMap).getBytes();
            } else {
                rglog.error("签名验证失败!");
                xmlTreeUtil.setXmlTreeStringValue(UpacTreeNodeConstant.respCode, "11");
                xmlTreeUtil.setXmlTreeStringValue(UpacTreeNodeConstant.respDesc, "验证签名失败");
                return new byte[0];
            }
        }
        return bytes;
    }

    @Override
    public int afterInComPackSwitch() throws Exception {
        RgLogger rglog = RgLog.getLogger(this.getClass().getName());
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        String txnType = xmlTreeUtil.getXmlTreeStringValue("upacTxnType");
        String txnSubType = xmlTreeUtil.getXmlTreeStringValue("txnSubType");
        if (xmlTreeUtil.isExist(UpacTreeNodeConstant.settleDate)) {
            String settleDate = xmlTreeUtil.getXmlTreeStringValue(UpacTreeNodeConstant.settleDate);
            if (settleDate.length() == 4) {
                xmlTreeUtil.setXmlTreeStringValue(UpacTreeNodeConstant.settleDate, getCupsSettleDate(settleDate));
            }
        }
        switch (txnType) {
            case "79"://开通通知
                xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.TXN_NUM, "T00CH100");
                break;
            case "01"://消费通知
                xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.TXN_NUM, "P01CH101");
                break;
            case "31"://消费撤销通知
                xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.TXN_NUM, "P01CH102");
                break;
            case "04"://消费退货通知
                xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.TXN_NUM, "P04CH101");
                break;
            case "11"://代收通知
                xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.TXN_NUM, "P01CH103");
                break;
            case "12"://代付通知
                xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.TXN_NUM, "P01CH104");
                break;
            default:
                rglog.info("未知通知类型[{}]", txnType + txnSubType);
        }
        return 0;
    }

    @Override
    public int beforeOutgoPackSwitch() throws Exception {
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        xmlTreeUtil.setXmlTreeStringValue("_MESSAGEHEAD/http/Content-Type", "application/x-www-form-urlencoded");
        return 0;
    }

    @Override
    public byte[] afterOutgoPackSwitch(byte[] bytes) throws Exception {
        return "ok".getBytes();
    }

    String getCupsSettleDate(String settleDate) {
        String yearSettleDate = DateUtil.getCurrentDate();
        String year = yearSettleDate.substring(0, 4);
        String month = yearSettleDate.substring(4, 6);
        String settleMonth = settleDate.substring(0, 2);
        if ("01".equals(settleMonth) && "12".equals(month)) {
            return String.format("%d", Integer.parseInt(year) + 1) + settleDate;
        } else if ("12".equals(settleMonth) && "01".equals(month)) {

            return String.format("%d", Integer.parseInt(year) - 1) + settleDate;
        }
        return year + settleDate;
    }
}
